﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace Assets.Scripts.Tool
{
    /// <summary>
    /// 功能：公式计算
    /// 作者：陈林
    /// 修改时间：2017/11/1
    /// </summary>
    public class FormulaCalculator
    {

        private bool isRightFormat = true;//是否是正确的公式
        private bool isRightArgs = true;//是否是正确的参数
        private float GetResult(string formula)
        {
            float value = 0;
            try
            {
                string changeValue = ChangeFormulaFormat(formula);
                value = DoAnalysis(changeValue);
            }
            catch (Exception e)
            {
                Debug.Log(e.ToString());
            }
            if (!isRightFormat)
            {
                Debug.Log("公式格式有误，请检查："+formula);
                return default(float);
            }
            if (!isRightArgs)
            {
                Debug.Log("参数错误");
                return default(float);
            }
            return value;
        }

        /// <summary>
        /// 得到结果
        /// </summary>
        /// <param name="formula">公式</param>
        /// <param name="decimalPlace">保留小数点的位数</param>
        /// <returns></returns>
        public string GetResult(string formula,int decimalPlace)
        {
            float result = GetResult(formula);
            if (Math.Abs(result - float.MaxValue) < 0.001f)
            {
                return "0.0";//返回0
            }
            else
            {
                if (decimalPlace > 0)
                {
                    return NumberAround(result, decimalPlace);
                }
                else
                {
                    return Mathf.RoundToInt((float)result).ToString();
                }
            }
        }

       
        /// <summary>
        /// 保留小数点的为主
        /// </summary>
        /// <param name="dN"></param>
        /// <param name="decimalPlace"></param>
        /// <returns></returns>
        public string NumberAround(float dN, int decimalPlace)
        {
            int temp = Mathf.RoundToInt((float) (dN*Math.Pow(10, decimalPlace)));
            string reslut = ((float)temp / Math.Pow(10, decimalPlace)).ToString();
            if (!reslut.Contains("."))//说明结果是整数
            {
                reslut = reslut + '.';
                for (int i = 0; i < decimalPlace; i++)
                {
                    reslut += '0';
                }
            }
            else
            {
                string[] str= reslut.Split('.');
                if (str[1].Length < decimalPlace)
                {
                    for (int i = 0; i < decimalPlace-str[1].Length; i++)
                    {
                        reslut += '0';
                    }    
                }
            }
            return reslut;
        }

        private float DoAnalysis(string formula)
        {
            float value = 0;
            List<int>stack=new List<int>();
            int curPos = 0;
            string beforePart = "";
            string afterPart = "";
            string calculator = "";
            isRightFormat = true;
            while (isRightFormat&&formula.IndexOf("(")>0||formula.IndexOf(")")>0||formula.IndexOf("（")>0||formula.IndexOf("）")>0) //添加对中文左右括号的支持
            {
                curPos = 0;
                foreach (char s in formula)
                {
                    if (s == '('||s=='（')
                    {
                        stack.Add(curPos); 
                    }
                    else if (s == ')'||s=='）')
                    {
                        if (stack.Count > 0)
                        {                            
                            beforePart = formula.Substring(0, stack[stack.Count - 1]);
                            afterPart = formula.Substring(curPos + 1);
                            calculator = formula.Substring(stack[stack.Count - 1] + 1, curPos - (stack[stack.Count - 1] + 1));
                            formula = beforePart + DoCalcultation(calculator) + afterPart;
                            stack.Clear();
                            break;
                        }
                        else
                        {                            
                            Debug.Log("有未关闭的右括号");
                            isRightFormat = false;
                        }
                    }
                    curPos++;
                }
                if (stack.Count > 0)
                {
                    Debug.Log("有未关闭的左括号"); 
                    isRightFormat = false;//这里之前忘记加判断
                }
            }
            if (isRightFormat)
            {
                value = DoCalcultation(formula);
            }
            return value;
        }


        /// <summary>
        /// 改变公式的格式
        /// </summary>
        private string ChangeFormulaFormat(string formula)
        {
            StringBuilder value=new StringBuilder(formula);
            for (int i = 0; i < value.Length; i++)
            {
                if (i >= 1)
                {
                    //Debug.Log("value[i]："+value[i]+"  value[i-1]："+value[i-1]);
                    if (value[i] =='-'&&(value[i-1]>='0'&&value[i-1]<='9'||value[i-1]==')'))//"-"前面是数字,不能使用数字要使用字符
                    {
                        value[i] = '#';
                    }
                }
            }
            //Debug.Log("changedFormula:" + value);
            return value.ToString();
        }

        /// <summary>
        /// 为了区分负号，这边使用#代替减号
        /// </summary>
        /// <param name="formula"></param>
        /// <returns></returns>
        private float DoCalcultation(string formula)
        {
            List<float> values=new List<float>();
            List<string> operators=new List<string>();
            int prePos = 0;
            int curPos = 0;
            foreach (char s in formula)
            {
                if (s == '+' || s == '#' || s == '*' || s == '/' || s == '^')
                {
                    float value = float.Parse(formula.Substring(prePos, curPos - prePos));
                    values.Add(value);
                    //Debug.Log("value："+value);
                    operators.Add("" + s);                   
                    prePos = curPos + 1;
                }
                curPos++;
            }
            values.Add(float.Parse(formula.Substring(prePos)));
            for (int i = 0; i < operators.Count; i++)
            {
                switch (operators[i])
                {
                    case "^":
                        //偶次数开方并且被开放数小于0，触发参数错误
                        if ((1 / values[i + 1])%2 == 0&&values[i]<0)
                        {
                            isRightArgs = false;
                            values[i] = default(float);
                        }
                        else
                        {
                            //Debug.Log("values[i]:" + values[i] + "  values[i+1]:" + values[i + 1]);
                            values[i] = Mathf.Pow(values[i], values[i + 1]);
                            //Debug.Log("values[i]:" + values[i]);
                        }
                        values.RemoveAt(i + 1);
                        operators.RemoveAt(i);
                        i--;
                        break;
                }
            }
            for (int i = 0; i < operators.Count; i++)
            {
                switch (operators[i])
                {
                    case "*":
                        //Debug.Log("values[i]:" + values[i] + "  values[i+1]:" + values[i + 1]);
                        values[i] = values[i] * values[i + 1];
                        //Debug.Log("values[i]:" + values[i]);
                        values.RemoveAt(i + 1);
                        operators.RemoveAt(i);
                        i--;
                        break;
                    case "/":
                        if (values[i + 1] == 0)//除数为0
                        {
                            isRightArgs = false;
                            values[i] = default(float);
                        }
                        else
                        {
                            //Debug.Log("values[i]:" + values[i] + "  values[i+1]:" + values[i + 1]);
                            values[i] = values[i] / values[i + 1];
                            //Debug.Log("values[i]:" + values[i]);
                            values.RemoveAt(i + 1);
                            operators.RemoveAt(i);
                            i--;
                        }
                       
                        break;
                }
            }
            for (int i = 0; i < operators.Count; i++)
            {
                switch (operators[i])
                {
                    case "+":
                        //Debug.Log("values[i]:" + values[i] + "  values[i+1]:" + values[i + 1]);
                        values[i] = values[i] + values[i + 1];
                        //Debug.Log("values[i]:" + values[i]);
                        values.RemoveAt(i + 1);
                        operators.RemoveAt(i);
                        i--;
                        break;
                    case "#":
                        //Debug.Log("values[i]:" + values[i] + "  values[i+1]:" + values[i + 1]);
                        values[i] = values[i] - values[i + 1];
                        //Debug.Log("values[i]:" + values[i]);
                        values.RemoveAt(i + 1);
                        operators.RemoveAt(i);
                        i--;//将指针返回
                        break;
                }
            }                  
            return values[0];     
        }     
    }
}